// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   OmpressData.java

package com.iso8583.util;


public class OmpressData
{

    private OmpressData()
    {
    }

    public static OmpressData getInstance()
    {
        return singleton;
    }

    public static char[] encodeHex(byte data[])
    {
        int l = data.length;
        char out[] = new char[l << 1];
        int i = 0;
        int j = 0;
        for(; i < l; i++)
        {
            out[j++] = DIGITS[(0xf0 & data[i]) >>> 4];
            out[j++] = DIGITS[0xf & data[i]];
        }

        return out;
    }

    private static long getSym(long x)
    {
        long i = 1L;
        for(long j = 314L; i < j;)
        {
            long k = (i + j) / 2L;
            if(symCum[(int)k] > x)
                i = k + 1L;
            else
                j = k;
        }

        return i;
    }

    private static long getPos(long x)
    {
        long i = 1L;
        for(long j = 4096L; i < j;)
        {
            long k = (i + j) / 2L;
            if(posCum[(int)k] > x)
                i = k + 1L;
            else
                j = k;
        }

        return i - 1L;
    }

    private static void addNode(long n)
    {
        long cmp = 1L;
        int key = (int)n;
        long j = 4097 + dataBuf[key];
        rNode[(int)n] = lNode[(int)n] = 4096L;
        matchLen = 0L;
        do
        {
            long i;
            do
            {
                if(cmp >= 0L)
                {
                    if(rNode[(int)j] != 4096L)
                    {
                        j = rNode[(int)j];
                    } else
                    {
                        rNode[(int)j] = n;
                        fNode[(int)n] = j;
                        return;
                    }
                } else
                if(lNode[(int)j] != 4096L)
                {
                    j = lNode[(int)j];
                } else
                {
                    lNode[(int)j] = n;
                    fNode[(int)n] = j;
                    return;
                }
                for(i = 1L; i < 60L; i++)
                    if((cmp = dataBuf[(int)((long)key + i)] - dataBuf[(int)(j + i)]) != 0L)
                        break;

            } while(i <= 2L);
            long temp;
            if(i > matchLen)
            {
                matchPos = n - j & 4095L;
                if((matchLen = i) >= 60L)
                    break;
            } else
            if(i == matchLen && (temp = n - j & 4095L) < matchPos)
                matchPos = temp;
        } while(true);
        fNode[(int)n] = fNode[(int)j];
        lNode[(int)n] = lNode[(int)j];
        rNode[(int)n] = rNode[(int)j];
        fNode[(int)lNode[(int)j]] = n;
        fNode[(int)rNode[(int)j]] = n;
        if(rNode[(int)fNode[(int)j]] == j)
            rNode[(int)fNode[(int)j]] = n;
        else
            lNode[(int)fNode[(int)j]] = n;
        fNode[(int)j] = 4096L;
    }

    private static void delNode(long n)
    {
        if(fNode[(int)n] == 4096L)
            return;
        long i;
        if(rNode[(int)n] == 4096L)
            i = lNode[(int)n];
        else
        if(lNode[(int)n] == 4096L)
        {
            i = rNode[(int)n];
        } else
        {
            i = lNode[(int)n];
            if(rNode[(int)i] != 4096L)
            {
                do
                    i = rNode[(int)i];
                while(rNode[(int)i] != 4096L);
                rNode[(int)fNode[(int)i]] = lNode[(int)i];
                fNode[(int)lNode[(int)i]] = fNode[(int)i];
                lNode[(int)i] = lNode[(int)n];
                fNode[(int)lNode[(int)n]] = i;
            }
            rNode[(int)i] = rNode[(int)n];
            fNode[(int)rNode[(int)n]] = i;
        }
        fNode[(int)i] = fNode[(int)n];
        if(rNode[(int)fNode[(int)n]] == n)
            rNode[(int)fNode[(int)n]] = i;
        else
            lNode[(int)fNode[(int)n]] = i;
        fNode[(int)n] = 4096L;
    }

    private static void updateNode(long sym)
    {
        long i;
        if(symCum[0] >= 32767L)
        {
            long j = 0L;
            for(i = 314L; i > 0L; i--)
            {
                symCum[(int)i] = j;
                j += symFreq[(int)i] = symFreq[(int)i] + 1L >> 1;
            }

            symCum[0] = j;
        }
        for(i = sym; symFreq[(int)i] == symFreq[(int)(i - 1L)]; i--);
        if(i < sym)
        {
            long k = symChar[(int)i];
            long ch = symChar[(int)sym];
            symChar[(int)i] = ch;
            symChar[(int)sym] = k;
            charSym[(int)k] = sym;
            charSym[(int)ch] = i;
        }
        for(symFreq[(int)i]++; --i > 0L; symCum[(int)i]++);
        symCum[0]++;
    }

    private static short[] bytesToShorts(byte byteArray[])
    {
        short shortArray[] = new short[byteArray.length];
        for(int i = 0; i < shortArray.length; i++)
        {
            shortArray[i] = byteArray[i];
            shortArray[i] &= 0xff;
        }

        return shortArray;
    }

    private static byte[] shortsTobytes(short shortArray[])
    {
        byte byteArray[] = new byte[shortArray.length];
        for(int i = 0; i < byteArray.length; i++)
            byteArray[i] = (byte)shortArray[i];

        return byteArray;
    }

    public static synchronized byte[] deCompressData(byte byteSrcbuf[], int srclen)
        throws Exception
    {
        short ch = 0;
        short mask = 0;
        long low = 0L;
        long value = 0L;
        long high = 0x20000L;
        int sp = 0;
        int dp = 0;
        short srcbuf[] = bytesToShorts(byteSrcbuf);
        long i = srcbuf[sp++];
        i <<= 8;
        i += srcbuf[sp++];
        i <<= 8;
        i += srcbuf[sp++];
        i <<= 8;
        i += srcbuf[sp++];
        if(i > 8192L)
            throw new Exception("Decompress Error!");
        short dstbuf[] = new short[(int)i];
        int srcend = srclen;
        int dstend = (int)i;
        for(i = 0L; i < 17L; i++)
        {
            value *= 2L;
            if((mask >>= 1) == 0)
            {
                ch = sp < srcend ? srcbuf[sp++] : 0;
                mask = 128;
            }
            value += (ch & mask) == 0 ? 0 : 1;
        }

        symCum[314] = 0L;
        for(long k = 314L; k >= 1L; k--)
        {
            long j = k - 1L;
            charSym[(int)j] = k;
            symChar[(int)k] = j;
            symFreq[(int)k] = 1L;
            symCum[(int)(k - 1L)] = symCum[(int)k] + symFreq[(int)k];
        }

        symFreq[0] = 0L;
        posCum[4096] = 0L;
        for(i = 4096L; i >= 1L; i--)
            posCum[(int)(i - 1L)] = posCum[(int)i] + 10000L / (i + 200L);

        for(i = 0L; i < 4036L; i++)
            dataBuf[(int)i] = 32;

        long r = 4036L;
        while(dp < dstend) 
        {
            long range = high - low;
            long sym = getSym((((value - low) + 1L) * symCum[0] - 1L) / range);
            high = low + (range * symCum[(int)(sym - 1L)]) / symCum[0];
            low += (range * symCum[(int)sym]) / symCum[0];
            do
            {
                if(low >= 0x10000L)
                {
                    value -= 0x10000L;
                    low -= 0x10000L;
                    high -= 0x10000L;
                } else
                if(low >= 32768L && high <= 0x18000L)
                {
                    value -= 32768L;
                    low -= 32768L;
                    high -= 32768L;
                } else
                if(high > 0x10000L)
                    break;
                low += low;
                high += high;
                value *= 2L;
                if((mask >>= 1) == 0)
                {
                    ch = sp < srcend ? srcbuf[sp++] : 0;
                    mask = 128;
                }
                value += (ch & mask) == 0 ? 0 : 1;
            } while(true);
            long c = symChar[(int)sym];
            updateNode(sym);
            if(c < 256L)
            {
                if(dp >= dstend)
                    throw new Exception("Decompress Error!");
                dstbuf[dp++] = (short)(int)c;
                dataBuf[(int)(r++)] = (short)(int)c;
                r &= 4095L;
            } else
            {
                long j = (c - 255L) + 2L;
                range = high - low;
                i = getPos((((value - low) + 1L) * posCum[0] - 1L) / range);
                high = low + (range * posCum[(int)i]) / posCum[0];
                low += (range * posCum[(int)(i + 1L)]) / posCum[0];
                do
                {
                    if(low >= 0x10000L)
                    {
                        value -= 0x10000L;
                        low -= 0x10000L;
                        high -= 0x10000L;
                    } else
                    if(low >= 32768L && high <= 0x18000L)
                    {
                        value -= 32768L;
                        low -= 32768L;
                        high -= 32768L;
                    } else
                    if(high > 0x10000L)
                        break;
                    low += low;
                    high += high;
                    value *= 2L;
                    if((mask >>= 1) == 0)
                    {
                        ch = sp < srcend ? srcbuf[sp++] : 0;
                        mask = 128;
                    }
                    value += (ch & mask) == 0 ? 0 : 1;
                } while(true);
                i = r - i - 1L & 4095L;
                for(long k = 0L; k < j; k++)
                {
                    c = dataBuf[(int)(i + k & 4095L)];
                    if(dp >= dstend)
                        throw new Exception("Decompress Error!");
                    dstbuf[dp++] = (short)(int)c;
                    dataBuf[(int)(r++)] = (short)(int)c;
                    r &= 4095L;
                }

            }
        }
        return shortsTobytes(dstbuf);
    }

    public static synchronized byte[] Compress(byte byteSrcbuf[], int srclen)
    {
        long low = 0L;
        long shifts = 0L;
        long written = 4L;
        short ch = 0;
        short mask = 128;
        long high = 0x20000L;
        int srcend = srclen;
        int sp = 0;
        int dp = 0;
        short srcbuf[] = bytesToShorts(byteSrcbuf);
        short dstbuf[] = new short[8192];
        dstbuf[dp++] = (short)(srclen >> 24);
        dstbuf[dp++] = (short)(srclen >> 16);
        dstbuf[dp++] = (short)(srclen >> 8);
        dstbuf[dp++] = (short)srclen;
        symCum[314] = 0L;
        long k;
        for(k = 314L; k >= 1L; k--)
        {
            long j = k - 1L;
            charSym[(int)j] = k;
            symChar[(int)k] = j;
            symFreq[(int)k] = 1L;
            symCum[(int)(k - 1L)] = symCum[(int)k] + symFreq[(int)k];
        }

        symFreq[0] = 0L;
        posCum[4096] = 0L;
        for(long i = 4096L; i >= 1L; i--)
            posCum[(int)(i - 1L)] = posCum[(int)i] + 10000L / (i + 200L);

        for(long i = 4097L; i <= 4352L; i++)
            rNode[(int)i] = 4096L;

        for(long i = 0L; i < 4096L; i++)
            fNode[(int)i] = 4096L;

        long s = 0L;
        k = 4036L;
        for(long i = s; i < k; i++)
            dataBuf[(int)i] = 32;

        long len;
        for(len = 0L; len < 60L && sp < srcend; len++)
            dataBuf[(int)(k + len)] = srcbuf[sp++];

        for(long i = 1L; i <= 60L; i++)
            addNode(k - i);

        addNode(k);
        do
        {
            if(matchLen > len)
                matchLen = len;
            if(matchLen <= 2L)
            {
                matchLen = 1L;
                long sym = charSym[dataBuf[(int)k]];
                long range = high - low;
                high = low + (range * symCum[(int)(sym - 1L)]) / symCum[0];
                low += (range * symCum[(int)sym]) / symCum[0];
                do
                {
                    if(high <= 0x10000L)
                    {
                        if((mask >>= 1) == 0)
                        {
                            dstbuf[dp++] = ch;
                            ch = 0;
                            mask = 128;
                            written++;
                        }
                        for(; shifts > 0L; shifts--)
                        {
                            ch |= mask;
                            if((mask >>= 1) == 0)
                            {
                                dstbuf[dp++] = ch;
                                ch = 0;
                                mask = 128;
                                written++;
                            }
                        }

                    } else
                    if(low >= 0x10000L)
                    {
                        ch |= mask;
                        if((mask >>= 1) == 0)
                        {
                            dstbuf[dp++] = ch;
                            ch = 0;
                            mask = 128;
                            written++;
                        }
                        for(; shifts > 0L; shifts--)
                            if((mask >>= 1) == 0)
                            {
                                dstbuf[dp++] = ch;
                                ch = 0;
                                mask = 128;
                                written++;
                            }

                        low -= 0x10000L;
                        high -= 0x10000L;
                    } else
                    {
                        if(low < 32768L || high > 0x18000L)
                            break;
                        shifts++;
                        low -= 32768L;
                        high -= 32768L;
                    }
                    low += low;
                    high += high;
                } while(true);
                updateNode(sym);
            } else
            {
                long sym = charSym[(int)(253L + matchLen)];
                long range = high - low;
                high = low + (range * symCum[(int)(sym - 1L)]) / symCum[0];
                low += (range * symCum[(int)sym]) / symCum[0];
                do
                {
                    if(high <= 0x10000L)
                    {
                        if((mask >>= 1) == 0)
                        {
                            dstbuf[dp++] = ch;
                            ch = 0;
                            mask = 128;
                            written++;
                        }
                        for(; shifts > 0L; shifts--)
                        {
                            ch |= mask;
                            if((mask >>= 1) == 0)
                            {
                                dstbuf[dp++] = ch;
                                ch = 0;
                                mask = 128;
                                written++;
                            }
                        }

                    } else
                    if(low >= 0x10000L)
                    {
                        ch |= mask;
                        if((mask >>= 1) == 0)
                        {
                            dstbuf[dp++] = ch;
                            ch = 0;
                            mask = 128;
                            written++;
                        }
                        for(; shifts > 0L; shifts--)
                            if((mask >>= 1) == 0)
                            {
                                dstbuf[dp++] = ch;
                                ch = 0;
                                mask = 128;
                                written++;
                            }

                        low -= 0x10000L;
                        high -= 0x10000L;
                    } else
                    {
                        if(low < 32768L || high > 0x18000L)
                            break;
                        shifts++;
                        low -= 32768L;
                        high -= 32768L;
                    }
                    low += low;
                    high += high;
                } while(true);
                updateNode(sym);
                range = high - low;
                high = low + (range * posCum[(int)(matchPos - 1L)]) / posCum[0];
                low += (range * posCum[(int)matchPos]) / posCum[0];
                do
                {
                    if(high <= 0x10000L)
                    {
                        if((mask >>= 1) == 0)
                        {
                            dstbuf[dp++] = ch;
                            ch = 0;
                            mask = 128;
                            written++;
                        }
                        for(; shifts > 0L; shifts--)
                        {
                            ch |= mask;
                            if((mask >>= 1) == 0)
                            {
                                dstbuf[dp++] = ch;
                                ch = 0;
                                mask = 128;
                                written++;
                            }
                        }

                    } else
                    if(low >= 0x10000L)
                    {
                        ch |= mask;
                        if((mask >>= 1) == 0)
                        {
                            dstbuf[dp++] = ch;
                            ch = 0;
                            mask = 128;
                            written++;
                        }
                        for(; shifts > 0L; shifts--)
                            if((mask >>= 1) == 0)
                            {
                                dstbuf[dp++] = ch;
                                ch = 0;
                                mask = 128;
                                written++;
                            }

                        low -= 0x10000L;
                        high -= 0x10000L;
                    } else
                    {
                        if(low < 32768L || high > 0x18000L)
                            break;
                        shifts++;
                        low -= 32768L;
                        high -= 32768L;
                    }
                    low += low;
                    high += high;
                } while(true);
            }
            long LMatchLen = matchLen;
            long i;
            for(i = 0L; i < LMatchLen && sp < srcend; i++)
            {
                long j = srcbuf[sp++];
                delNode(s);
                dataBuf[(int)s] = (short)(int)j;
                if(s < 59L)
                    dataBuf[(int)(s + 4096L)] = (short)(int)j;
                s = s + 1L & 4095L;
                k = k + 1L & 4095L;
                addNode(k);
            }

            while(i++ < LMatchLen) 
            {
                delNode(s);
                s = s + 1L & 4095L;
                k = k + 1L & 4095L;
                if(--len != 0L)
                    addNode(k);
            }
        } while(len > 0L);
        shifts++;
        if(low < 32768L)
        {
            if((mask >>= 1) == 0)
            {
                dstbuf[dp++] = ch;
                ch = 0;
                mask = 128;
                written++;
            }
            for(; shifts > 0L; shifts--)
            {
                ch |= mask;
                if((mask >>= 1) == 0)
                {
                    dstbuf[dp++] = ch;
                    ch = 0;
                    mask = 128;
                    written++;
                }
            }

        } else
        {
            ch |= mask;
            if((mask >>= 1) == 0)
            {
                dstbuf[dp++] = ch;
                ch = 0;
                mask = 128;
                written++;
            }
            for(; shifts > 0L; shifts--)
                if((mask >>= 1) == 0)
                {
                    dstbuf[dp++] = ch;
                    ch = 0;
                    mask = 128;
                    written++;
                }

        }
        for(long i = 0L; i < 7L; i++)
            if((mask >>= 1) == 0)
            {
                dstbuf[dp++] = ch;
                ch = 0;
                mask = 128;
                written++;
            }

        return shortsTobytes(copyOf(dstbuf, (int)written));
    }

    public static short[] copyOf(short original[], int newLength)
    {
        short copy[] = new short[newLength];
        System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
        return copy;
    }

    public static void main(String args[])
        throws Exception
    {
        String ss = "000000a3fe5c2274220fa69705f92c90d7a57fdeb6bc6c4f8af637cea361385aab8a4ec3e34d43aa3c16dd87c40a601ef5ae88c7f871ef25e35fc7338ac9b3852f3f39231c76578dbcc714a153d1e99d5a39043281bdb15ff640e4e93200c402f562a3c6ed699d7367d897e47ca4c53d61ee5bc2af9312546e07fb18f5d17c3e9acdd800";
        byte src[] = hexStringToBytes(ss);
        byte bb[] = deCompressData(src, src.length);
        System.out.println(encodeHex(bb));
    }

    public static byte[] hexStringToBytes(String hexStr)
    {
        int length = hexStr.length();
        if(length % 2 != 0)
            throw new IllegalArgumentException();
        hexStr = hexStr.toUpperCase();
        byte outArray[] = new byte[length / 2];
        for(int i = 0; i < length; i += 2)
        {
            char li = hexStr.charAt(i);
            char lo = hexStr.charAt(i + 1);
            if(li < '0' || li > 'F' || lo < '0' || lo > 'F')
                throw new IllegalArgumentException();
            outArray[i / 2] = (byte) Integer.parseInt(String.valueOf(new char[]{
                    li, lo
            }), 16);
        }

        return outArray;
    }

    private static OmpressData singleton = new OmpressData();
    private static final int MAX_BUFFER_SIZE = 8192;
    private static short dataBuf[] = new short[4200];
    private static long charSym[] = new long[320];
    private static long symChar[] = new long[320];
    private static long symFreq[] = new long[320];
    private static long symCum[] = new long[320];
    private static long posCum[] = new long[4100];
    private static long matchPos;
    private static long matchLen;
    private static long lNode[] = new long[4100];
    private static long rNode[] = new long[4360];
    private static long fNode[] = new long[4100];
    private static final char DIGITS[] = {
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 
        'a', 'b', 'c', 'd', 'e', 'f'
    };

}
